package com.googlecode.lightest.studio

import com.googlecode.lightest.core.IConfiguration
import com.googlecode.lightest.core.IDispatcherAssignmentStrategy
import com.googlecode.lightest.core.ITestEnvironment
import com.googlecode.lightest.core.LightestTestListener
import com.googlecode.lightest.core.IPreferences

/**
 *
 * @author chai
 */
class Configuration implements IConfiguration {
    String outputDir
    String reporterClassName
    String dispatcherAssignmentStrategyClassName
    Preferences prefs

    static hasMany = [
        classPathEntries: ClassPathEntry,
        testEnvironments: TestEnvironment
    ]

    static constraints = {
        outputDir (blank: false, validator: { CommonConstraints.dirOk(it) })
        reporterClassName (blank: false)
        dispatcherAssignmentStrategyClassName (blank: false)
    }

    static transients = [
        'classLoader',
        'classPaths',
        'environment',
        'preferences',
        'reporter',
        'dispatcherAssignmentStrategy'
    ]

    /**
     * Returns the class loader used to load the configuration-related classes.
     */
    GroovyClassLoader getClassLoader() {
        def classLoader = new GroovyClassLoader()
        LightestUtils.addClassPaths(getClassPaths(), classLoader)
        return classLoader
    }

    /**
     * Returns a List of Strings representing class paths under which tasks
     * and potentially environment and preference classes are defined. The
     * current directory is added by default.
     */
    List<String> getClassPaths() {
        def classPaths = [ '.' ]
        classPaths.addAll(classPathEntries.collect { it.value })
        return classPaths
    }

    /**
     * Returns a List of ITestEnvironment instances.
     */
    List<ITestEnvironment> getEnvironments() {
        def envs = []
        def classLoader = getClassLoader()

        for (testEnvironment in testEnvironments) {
            def env = Class.forName(testEnvironment.className, true,
                classLoader)

            for (pair in testEnvironment.nameValuePairs) {
                env."${pair.name}" = pair.value
            }

            env.id = testEnvironment.name
            envs << env
        }

        return envs
    }

    /**
     * Returns an instance of the concrete implementation of IPreferences.
     */
    IPreferences getPreferences() {
        def classLoader = getClassLoader()
        def prefs = Class.forName(preferences.className, true, classLoader)

        for (pair in preferences.nameValuePairs) {
            prefs."${pair.name}" = pair.value
        }

        return prefs
    }

    /**
     * Returns an instance of the concrete implementation of IReporter.
     */
    LightestTestListener getReporter() {
        def classLoader = getClassLoader()
        def reporterClass = Class.forName(reporterClassName, true, classLoader)

        // TODO - handle errors more gracefully!!
        assert LightestTestListener.class.isAssignableFrom(reporterClass)

        return reporterClass.newInstance()
    }

    IDispatcherAssignmentStrategy getDispatcherAssignmentStrategy() {
        def strategyClass = Class.forName(dispatcherAssignmentStrategyClassName,
            true, getClassLoader())

        // TODO - handle errors more gracefully!!
        assert IDispatcherAssignmentStrategy.class.isAssignableFrom(
            strategyClass)

        return strategyClass.newInstance()
    }	
}

